package com.xy.template;

import cn.hutool.json.JSONUtil;
import com.xy.core.constant.PathUtil;
import com.xy.system.mode.CodeMode;
import com.xy.system.mode.TemplateSet;
import com.xy.system.mode.TemplateVO;
import com.xy.template.constant.JavaNameUtil;
import com.xy.template.constant.MetadataUtil;
import com.xy.template.model.Attribute;
import com.xy.template.model.FtlContext;
import com.xy.template.model.PageAttribute;
import com.xy.template.model.PageAttributeRow;

import java.io.*;
import java.nio.charset.Charset;
import java.util.*;
import java.util.function.Predicate;

/**
 * ftl服务
 */
public class FtlServer {

    /**
     * 表单
     *
     * @return
     * @throws Exception
     */
    public static List<PageAttributeRow> assemblyForm(List<PageAttribute> list) throws Exception {
        List<PageAttributeRow> resList = new ArrayList<>();
        int pageRow = PageAttribute.FORM_WIDTH_SIZE;
        int nowLeft = pageRow;
        PageAttributeRow nowRow = new PageAttributeRow();
        int width = 0;
        for (PageAttribute item : list) {
            width = item.getWidthNum();
            if (width > nowLeft) {
                if (nowRow.getRowList().size() > 0) {
                    resList.add(nowRow);
                }
                nowRow = new PageAttributeRow();
                nowRow.getRowList().add(item);
                nowLeft = pageRow - width;
            } else {
                nowRow.getRowList().add(item);
                nowLeft = nowLeft - width;
            }
        }
        if (nowRow.getRowList().size() > 0) {
            resList.add(nowRow);
        }
        return resList;
    }

    /**
     * 查询条件
     *
     * @return
     * @throws Exception
     */
    public static List<PageAttributeRow> assemblyCond(List<PageAttribute> list) throws Exception {
        List<PageAttributeRow> resList = new ArrayList<>();
        int pageSize = 2;
        int len = list.size() / pageSize;
        if (list.size() % pageSize > 0) {
            len = len + 1;
        }
        int pos = 0;
        for (int index = 0; index < len; index++) {
            List<PageAttribute> nowList = new ArrayList<>();
            for (int z = 0; z < pageSize; z++) {
                pos = index * pageSize + z;
                if (pos >= list.size()) {
                    nowList.add(new PageAttribute());
                } else {
                    nowList.add(list.get(pos));
                }

            }
            PageAttributeRow newRow = new PageAttributeRow();
            newRow.setRowList(nowList);
            resList.add(newRow);
        }
        return resList;
    }

    /**
     * 过滤
     *
     * @return
     * @throws Exception
     */
    public static List<PageAttribute> filterCond(Map<String, PageAttribute> queryDataMap, Predicate<PageAttribute> predicate) throws Exception {
        List<PageAttribute> resList = new ArrayList<>();
        for (PageAttribute entry : queryDataMap.values()) {
            if (predicate.test(entry)) {
                resList.add(entry);
            }
        }
        Collections.sort(resList, new Comparator<PageAttribute>() {
            @Override
            public int compare(PageAttribute t0, PageAttribute t1) {
                return t0.getSortNum().compareTo(t1.getSortNum());
            }
        });
        return resList;
    }

    /**
     * 生成地址
     *
     * @param ctx
     * @return
     * @throws Exception
     */
    public static String build(FtlContext ctx) throws Exception {

        //加载模板
        CodeMode mode = CodeMode.getByCode(ctx.getSelectMode());
        if (mode == null) {
            System.out.println("该模式不支持");
            return "该模式不支持";
        }
        TemplateSet templateSet = CodeMode.getByCode(ctx.getSelectMode()).getNormalFileList();
        //固定变量
        Map<String, Object> context = new HashMap<String, Object>();
        context.put("basePackage", JavaNameUtil.getPackage(ctx.getSelectTableBaseDir()));
        context.put("basePath", JavaNameUtil.getPath(ctx.getSelectTableBaseDir()));
        context.put("tableName", ctx.getSelectTableNow());
        context.put("selectProjectName", ctx.getSelectProjectName());
        String[] dirs = ctx.getSelectTableBaseDir().split("\\.");
        String subTableName = ctx.getSelectTableNow();
        int firstSplit = subTableName.indexOf("_");
        //保护两个分割符号
        if (firstSplit > 0) {
            int secondSplit = subTableName.indexOf("_", firstSplit);
            if (secondSplit > 0) {
                subTableName = subTableName.substring(firstSplit + 1);
            }
        }
        String className = JavaNameUtil.toPascal(subTableName);
        String className2 = JavaNameUtil.toCamel(subTableName);
        context.put("className", className);
        context.put("className2", className2);
        context.put("className3", className.toLowerCase());

        String minPath = dirs[dirs.length - 1];
        context.put("minPath", minPath);
        String modulePath = dirs[dirs.length - 2];
        context.put("modulePath", modulePath);
        List<PageAttribute> queryItemList = filterCond(ctx.getCtrlDataMap(), f -> "Y".equals(f.getQueryShow()));
        List<PageAttribute> listItemList = filterCond(ctx.getCtrlDataMap(), f -> "Y".equals(f.getFormShow()));
        List<PageAttribute> formItemList = filterCond(ctx.getCtrlDataMap(), f -> "Y".equals(f.getListShow()));
        context.put("queryItemList", queryItemList);
        context.put("listItemList", listItemList);
        context.put("formItemList", formItemList);
        context.put("queryRowList", assemblyCond(queryItemList));
        context.put("formRowList", assemblyForm(formItemList));
        //Attribute里面封装模板使用属性
        List<Attribute> attrList = MetadataUtil.getTableColumnsInfo(ctx.getNowVO(), ctx.getSelectTableNow());
        int idx = 1;
        for (Attribute att : attrList) {
            att.setIdx(idx++);
            att.setCtrl(ctx.getCtrlDataMap().get(att.getCamelName()));
            if(att.getCtrl() == null){
                att.setCtrl(new PageAttribute());
            }
        }
        context.put("attrs", attrList);
        //生成路径
        String savePath = PathUtil.outDir() + "/todo_delete/" + System.currentTimeMillis();
        System.out.println("****上下文环境****");
        System.out.println(JSONUtil.toJsonPrettyStr(context));
        //轮询文件
        for (TemplateVO vo : templateSet.getFiles()) {
            String nowPath = savePath + "/" + vo.getPrePath() + "/";
            if (vo.isShortPath()) {
                nowPath += modulePath + "/" + minPath + "/";
            } else {
                nowPath += ctx.getSelectTableBaseDir() + "/";
            }
            nowPath = JavaNameUtil.getPath(nowPath, vo.getAfterPath());
            String packageName = JavaNameUtil.getPackage(ctx.getSelectTableBaseDir(), vo.getAfterPath());

            //获取模板
            freemarker.template.Template temp = templateSet.find(vo.getFtlName());
            context.put("packageName", packageName);
            String classFileName = vo.getPreName() + className + vo.getAfterName();
            if (vo.isShortName()) {
                classFileName = vo.getPreName() + className2 + vo.getAfterName();
            }
            File file = new File(nowPath, classFileName);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            OutputStream fos = new FileOutputStream(file);
            Writer out = new OutputStreamWriter(fos, Charset.forName("UTF-8"));
            try {
                temp.process(context, out);
            } catch (Exception ex) {
                ex.printStackTrace();
            } finally {
                try {
                    fos.flush();
                } catch (Exception ex) {
                }
                try {
                    fos.close();
                } catch (Exception ex) {
                }
                try {
                    out.close();
                } catch (Exception ex) {
                }
            }
        }
        //清理旧文件
        clearOldFile(new File(savePath));
        return savePath;
    }

    /**
     * 清理旧文件
     */
    private static void clearOldFile(File dir) {
        if (dir.isDirectory()) {
            for (File subFile : dir.listFiles()) {
                //三天前删除
                if (System.currentTimeMillis() - subFile.lastModified() > 1000 * 3600 * 24 * 3) {
                    deleteFile(subFile);
                }
            }
        }
    }

    /**
     * 删除文件
     *
     * @param dir
     */
    private static void deleteFile(File dir) {
        if (dir.isDirectory()) {
            for (File subFile : dir.listFiles()) {
                deleteFile(subFile);
            }
        }
        dir.setWritable(true);
        dir.setExecutable(true);
        dir.delete();
    }
}
